#!/usr/bin/env bash

###############################################################
# File Name: install_logstash.sh
# Version: V1.0
# Author: Brian Hsiung
# Created Time : 2025-01-21 9:37:53
# Description: Logstash部署脚本
##############################################################

# 调试跟踪（-e: 与错退出， -u: 捕获未定义的变量， -x: 调试模式，在执行每个命令前，将其打印到标准错误输出）
# set -eux

# 运行用户
declare -r LS_USER="elkuser"
# 运行版本
declare -r LS_VERSION="7.16.3"
# 安装目录
declare -r LS_BASE="/data/logstash"
# 软连接目录
declare -r LS_HOME="$LS_BASE/logstash"
# 日志目录
declare -r LS_LOG_DIR="$LS_HOME/logs"
# Elasticsearch用户名
declare -r ES_USERNAME="elastic"
# Elasticsearch密码
declare -r ES_PASSWORD="TawqcNpekz23wYrdAemL"
# 阿里云OSS存储地址
declare -r OSS_BASE_URL="https://brianhsiung.oss-cn-hangzhou.aliyuncs.com"
# Kafka集群地址
KAFKA_SERVERS="172.26.85.159:9092,172.26.85.160:9092,172.26.85.161:9092"
# Elasticsearch集群地址
ES_HOSTS=("172.26.85.159:9200" "172.26.85.160:9200" "172.26.85.161:9200")
# 生成带引号的数组
ES_HOSTS_STR=$(printf '"http://%s",' "${ES_HOSTS[@]}" | sed 's/,$//')

WORK_DIR="$(cd "$(dirname "$0")" && pwd)"
cd "$WORK_DIR" || exit

### 日志函数
log_info()    { echo -e "\033[34m[INFO] $*\033[0m"; }
log_warn()    { echo -e "\033[33m[WARNING] $*\033[0m"; }
log_success() { echo -e "\033[32m[SUCCESS] $*\033[0m"; }
log_error()   { echo -e "\033[31m[ERROR] $*\033[0m"; exit 1; }

##############################################
# 检查依赖
##############################################
check_dependency() {

    local -a required_cmds=("wget" "tar" "groupadd" "useradd")
    local missing=()

    log_info "检查依赖命令: ${required_cmds[*]}"
    for cmd in "${required_cmds[@]}"; do
        if ! command -v "$cmd" &>/dev/null; then
            missing+=("$cmd")
        fi
    done

    ((${#missing[@]})) && log_error "缺失依赖命令: ${missing[*]}"
}

##############################################
# 设置目录权限（递归检查上级目录）
##############################################
set_parent_permissions() {
    ### 某些等保三服务器默认新建的的目录权限为700，导致服务无法启动，所以需要遍历上级目录，将权限修改为755
    # 获取真实目录
    local target_dir
    target_dir=$(realpath "$1")
    # 获取上级目录
    local current_dir
    current_dir=$(dirname "$target_dir")

    # 做个判断，避免进入死循环
    [ -d "$target_dir" ] || log_error "目录不存在 [$target_dir]"

    # 排除敏感目录
    local -a exclude_dirs
    exclude_dirs=("/usr" "/usr/local" "/bin" "/sbin" "/lib" "/etc" "/dev" "/var" "/root" "/usr/share")

    while [[ "$current_dir" != "/" ]]; do
        # 排除敏感目录
        if printf '%s\n' "${exclude_dirs[@]}" | grep -qx "$current_dir"; then
            log_info "跳过系统保护目录: $current_dir"
            current_dir=$(dirname "$current_dir")
            continue
        fi

        # 跳过不存在的目录
        if [[ ! -d "$current_dir" ]]; then
            log_warn "警告: 目录不存在 [$current_dir]"
            current_dir=$(dirname "$current_dir")
            continue
        fi
        
        # 获取当前目录权限
        local perm_oct
        perm_oct=$(stat -c '%a' "$current_dir")
        log_info "目录 $current_dir 的原始权限为: $perm_oct"
        
        if [[ "$perm_oct" != "755" ]]; then
            log_info "正在设置权限: [755] -> $current_dir"
            if ! chmod 755 "$current_dir"; then
                log_error "错误: 无法设置目录权限 [$current_dir]"
            fi
        else
            log_success "权限正确 [755]: $current_dir"
        fi

        # 向上一级目录
        current_dir=$(dirname "$current_dir")
    done
}

install_logstash() {

	# 检查执行用户
	[[ "$(id -u)" -ne 0 ]] && log_error "请使用root用户执行此脚本"

	# 检查依赖
	check_dependency
    # 创建用户
    if ! getent group "$LS_USER" >/dev/null 2>&1; then
		log_info "创建用户组: $LS_USER"
        groupadd "$LS_USER"
    fi

    if ! getent passwd "$LS_USER" >/dev/null 2>&1; then
		log_info "创建用户: $LS_USER"
        useradd -g "$LS_USER" "$LS_USER"
    fi

	local cpu_type
	local logstash_pkg
	arch=$(uname -m)

	case "${arch}" in
		aarch64|arm64)
			cpu_type="aarch64"
			logstash_pkg="logstash-$LS_VERSION-linux-aarch64.tar.gz"
			;;
		amd64|x86_64)
			cpu_type="x64"
			logstash_pkg="logstash-$LS_VERSION-linux-x86_64.tar.gz"
			;;
		*)
			echo "不支持的CPU架构: $arch"
			exit 1
		;;
	esac

	# 下载安装包
	if curl -sIfo /dev/null --connect-timeout 5 --max-time 10 "$OSS_BASE_URL"/health; then
		if [ ! -f "$logstash_pkg" ]; then
			log_info "使用在线安装模式，下载安装包: $logstash_pkg"
			check_dependency "wget"
			wget -q "$OSS_BASE_URL/deploy/elastic/$cpu_type/$logstash_pkg" || log_error "$logstash_pkg 下载失败"
		fi
	else
        log_info "使用离线安装模式"
	fi

	[ -f "$logstash_pkg" ] || log_error "当前目录无 $logstash_pkg"

	# 解压安装包
	log_info "开始解压 $logstash_pkg"
	[  -d "$LS_BASE" ] || mkdir -p "$LS_BASE"
	tar -xzf "$logstash_pkg" -C "$LS_BASE" --no-same-owner || log_error "解压失败"

    # 创建软连接，方便升级
	### 处理软链接（强制更新指向）
    if [ -L "$LS_HOME" ]; then
        log_info "检测到旧软链接 $LS_HOME，即将更新指向..."
        ln -sfn "$LS_HOME"-"$LS_VERSION" "$LS_HOME" || log_error "软链接更新失败"
    elif [ -e "$LS_HOME" ]; then
        log_error "$LS_HOME 已存在且不是软链接，请手动处理"
    else
		log_info "创建软链接 $LS_HOME"
        ln -s "$LS_HOME"-"$LS_VERSION" "$LS_HOME" || log_error "软链接创建失败"
    fi

    [ -d "$LS_LOG_DIR" ] || mkdir -p "$LS_LOG_DIR"

	chown "$LS_USER":"$LS_USER" -R "$LS_BASE"
	set_parent_permissions "$LS_BASE"
}

add_logstash_conf() {
	log_info "添加配置文件"
    # 在执行前请修改下面内容中的bootstrap_servers连接地址，elasticsearch连接地址与其账号密码
	cat > $LS_HOME/config/logstash.conf << EOF
input {
	kafka {
		# kafka集群地址
		bootstrap_servers => "$KAFKA_SERVERS"
		# 运维平台上的sei.topic.logger.access和system对应的值
		topics => [ "SeiLoggerPlatform", "SeiLoggerAccess"]
		group_id => "Logstash"
		decorate_events => true
		auto_offset_reset => "latest"
		codec => "json"
	}
}

filter {
	if [logType] == "access" {
		mutate {
		lowercase => ["[env]"]
		add_tag => ["accesslog"]
		}
	} else {
		mutate {
			lowercase => ["[env]"]
			add_tag => ["kafka"]
		}
	}
}

output {
	if "kafka" in [tags] {
		elasticsearch {
		# elasticsearch集群连接地址
		hosts => [$ES_HOSTS_STR]
		index => "%{[serviceName]}-%{[env]}-%{+yyyy.MM.dd}-fromkafka"
		user => "$ES_USERNAME"
		# elasticsearch密码
		password => "$ES_PASSWORD"
		}
	}

	if "accesslog" in [tags] {
		elasticsearch {
			# elasticsearch集群连接地址
			hosts => [$ES_HOSTS_STR]
			index => "accesslog-%{[env]}-%{+yyyy.MM.dd}-fromkafka"
			user => "$ES_USERNAME"
			# elasticsearch密码
			password => "$ES_PASSWORD"
		}
	}
	# # 非容器部署时，注释stdout
	# stdout { 
	#   codec => rubydebug 
	# }
}
EOF
	### 更改权限
	chown "$LS_USER":"$LS_USER" $LS_HOME/config/logstash.conf
}

add_service() {
	log_info "添加服务"
	cat > /usr/lib/systemd/system/logstash.service << EOF
[Unit]
Description=Logstash
Documentation=https://www.elastic.co/cn/logstash
After=network-online.target
Wants=network-online.target

[Service]
Type=simple

User=$LS_USER
Group=$LS_USER

Environment="LS_HOME=$LS_HOME"

ExecStart=/bin/bash -c "$LS_HOME/bin/logstash -f $LS_HOME/config/logstash.conf"

Restart=on-failure

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    log_info "启动服务"
    systemctl enable --now logstash
    systemctl status logstash
}

main() {
	log_info "开始安装Logstash (版本: $LS_VERSION)"
	install_logstash
	add_logstash_conf
	add_service
	log_success "Logstash安装完成"
}

main